package com.rf.richfitwheel.admin.shiro;

import com.rf.richfitwheel.admin.contants.CustomToken;
import com.rf.richfitwheel.admin.sys.controller.SysDicController;
import com.rf.richfitwheel.admin.sys.model.User;
import com.rf.richfitwheel.admin.sys.service.SysUserAuthService;
import com.rf.richfitwheel.admin.sys.vo.UserVO;
import com.rf.richfitwheel.admin.utils.UserUtil;
import com.rf.richfitwheel.common.contants.Constant;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;

/**
 * 自定义Realm,进行数据源配置
 * 重写这个类，不走服务调用验证session
 */
public class UserRealm extends AuthorizingRealm {

    private static Logger log = LoggerFactory.getLogger(UserRealm.class);
    @Autowired
    @Lazy
    private SysUserAuthService sysUserAuthService;
//	@Autowired
//	private FSysUserAuthService fSysUserAuthService;

    /**
     * 只有需要验证权限时才会调用, 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        try {
            String loginName = SecurityUtils.getSubject().getPrincipal().toString();
            if (loginName != null) {
                UserVO user = UserUtil.getUser();
                // String userId = (String) SecurityUtils.getSubject().getSession().getAttribute("userSessionId");
                List<Map<String, Object>> rs = sysUserAuthService.getResourcesByUserId(user.getId());

                // 权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                // 用户的角色集合
                // info.addRole("default");
                // 用户的角色集合
                // info.setRoles(user.getRolesName());
                // 用户的角色对应的所有权限
                for (Map<String, Object> r : rs) {
                    info.addStringPermission((String) r.get("perms"));
                }
                return info;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 认证回调函数,登录时调用
     * 首先根据传入的用户名获取User信息；然后如果user为空，那么抛出没找到帐号异常UnknownAccountException；
     * 如果user找到但锁定了抛出锁定异常LockedAccountException；最后生成AuthenticationInfo信息，
     * 交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配，
     * 如果不匹配将抛出密码错误异常IncorrectCredentialsException；
     * 另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException；
     * 在组装SimpleAuthenticationInfo信息时， 需要传入：身份信息（用户名）、凭据（密文密码）、盐（username+salt），
     * CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//		try {
//			String username = (String) token.getPrincipal();
        CustomToken upToken = (CustomToken) token;
        // 获取用户名即可
        String username = upToken.getUsername();
        String tenantId = upToken.getTenantId();
        User user = new User();
        user.setUsername(username);
		/*if(StringUtils.isNotBlank(tenantId)) {
			user.setTenantId(tenantId);
		}*/
        //List<User> userList = null;
        UserVO userVO = null;
        try {
            //userList = sysUserAuthService.getUser(user);
            userVO = sysUserAuthService.getUserVoByUsername(username);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new UnknownAccountException();// 没找到帐号
        }
//			List<User> userList = fSysUserAuthService.getUser(user);
        if (ObjectUtils.isEmpty(userVO)) {
            throw new UnknownAccountException();// 没找到帐号
        }
        if (Constant.USER_STATUS_DISABLED.equals(userVO.getStatus())) {
            throw new DisabledAccountException();// 停用了
        }
        if (Constant.USER_STATUS_LOCKED.equals(userVO.getStatus())) {
            throw new LockedAccountException();// 锁定了
        }
        if (Constant.USER_STATUS_DELETED.equals(userVO.getStatus())) {
            throw new UnknownAccountException();// 帐号状态为删除
        }

        //id为"1"的用户为内置系统管理员，需要过滤掉
			/*if(Constant.TerminalType.TRUSTEE_PC.getValue().equals(upToken.getTerminal()) && !"1".equals(userList.get(0).getId()) && !Constant.COMMON_YES_OR_NO_YES.equals(userList.get(0).getIsCouncil()) ) {
				throw new UnknownAccountException();// 没找到帐号
			}else if(Constant.TerminalType.ENTRUST_PC.getValue().equals(upToken.getTerminal()) && !Constant.COMMON_YES_OR_NO_YES.equals(userList.get(0).getIsBussMng())) {
				throw new UnknownAccountException();// 没找到帐号
			}*/
        // 从数据库查询出来的账号名和密码,与用户输入的账号和密码对比
        // 当用户执行登录时,在方法处理上要实现user.login(token);
        // 然后会自动进入这个类进行认证
        // 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userVO, // 用户
                userVO.getPassword(), // 密码
                ByteSource.Util.bytes(username + userVO.getSalt()),// salt=username+salt
                getName() // realm name
        );

        // 当验证都通过后，把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute(Constant.USERSESSION, userVO);
			/*//获取所属部门
			 * 如果这个放入session的话每个项目都要引入Org实体类，否则shiro从redis获取session后无法正常转换为session类型
			if(userList.get(0).getOrgId() != null) {
				Org org = sysUserAuthService.getOrg(userList.get(0).getOrgId());
				session.setAttribute(Constant.USER_ORG_SESSION, org);
			}*/
        return authenticationInfo;

//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return null;
    }

    /**
     * 更新用户授权信息缓存.
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 更新用户信息缓存.
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    /**
     * 清除用户授权信息缓存.
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    /**
     * 清除用户信息缓存.
     */
    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    /**
     * 清空所有缓存
     */
    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }


    /**
     * 清空所有认证缓存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

}